package com.api.tournament.service.impl;

import com.api.core.ServiceException;
import com.api.tournament.contonst.Const;
import com.api.tournament.dao.*;
import com.api.tournament.model.*;
import com.api.tournament.service.RoundLogService;
import com.api.core.service.AbstractService;
import com.api.tournament.vo.SwapRoundVo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

import com.api.common.JSONUtils;
import com.api.core.response.Result;
import com.api.core.response.ResultGenerator;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

/**
 * Created by wanghuiwen on 2021/03/23.
 */
@Service
@Transactional
public class RoundLogServiceImpl extends AbstractService<RoundLog> implements RoundLogService {
    @Resource
    private RoundLogMapper roundLogMapper;
    @Resource
    private StageMapper stageMapper;
    @Resource
    private TournamentTeamMapper tournamentTeamMapper;
    @Resource
    private RoundMapper roundMapper;
    @Resource
    private StageRankMapper stageRankMapper;

    @Override
    public Result list(String search, String order, Integer page, Integer size){
        Map<String, Object> params = JSONUtils.json2map(search);
        Map<String, Object> orderParams = JSONUtils.json2map(order);
        for (String key : orderParams.keySet()) {
                if (orderParams.get(key) != null && orderParams.get(key).equals("ascending")) orderParams.put(key, "asc");
                if (orderParams.get(key) != null && orderParams.get(key).equals("descending")) orderParams.put(key, "desc");
            }
        PageHelper.startPage(page, size);
        List<Map<String, Object>> res = roundLogMapper.baseList(params, orderParams);
        PageInfo<Map<String, Object>> pageInfo = new PageInfo<>(res);
        return ResultGenerator.genSuccessResult(pageInfo);
    }

    @Override
    public Result rank(Long roundLogId, Integer aScore, Integer bScore, Long win, String aImages, String bImages) {
        Long loserId;
        RoundLog roundLog = findById(roundLogId);
        RoundLog oldRoundLog = new RoundLog();
        if(aScore.equals(bScore)){
            win = 0L;
        }
        if(roundLog.getResult()!=null){
            //修改成绩
            oldRoundLog.setRoundId(roundLog.getRoundId());
            oldRoundLog.setResult(roundLog.getResult());
            oldRoundLog.setTournamentUserIdA(roundLog.getTournamentUserIdA());
            oldRoundLog.setTournamentUserIdB(roundLog.getTournamentUserIdB());
            oldRoundLog.setType(roundLog.getType());
            oldRoundLog.setStageId(roundLog.getStageId());
            oldRoundLog.setaScore(roundLog.getaScore());
            oldRoundLog.setbScore(roundLog.getbScore());
            oldRoundLog.setRoundLogId(oldRoundLog.getRoundLogId());
        }
        roundLog.setaScore(aScore);
        roundLog.setaImages(aImages);
        roundLog.setResult(win);
        if(roundLog.getTournamentUserIdB()!=null){
            roundLog.setbScore(bScore);
            roundLog.setbImages(bImages);
        }
        update(roundLog);
        if(roundLog.getTournamentUserIdA().equals(win)){
            loserId = roundLog.getTournamentUserIdB();
        }else {
            loserId = roundLog.getTournamentUserIdA();
        }
        Stage stage =stageMapper.selectByPrimaryKey(roundLog.getStageId());

        if(stage.getFormat().equals(Const.GAME_FORMAT_DOUBLE)|| stage.getFormat().equals(Const.GAME_FORMAT_SINGLE)){
            if(win == 0) throw  new ServiceException("Double elimination and sigle elimination are not allowed to draw");
        }

        //改变获胜数量
        //修改阶段排名
        StageRank stageRankA = stageRankMapper.findByStageIdAndUserId(roundLog.getStageId(),roundLog.getTournamentUserIdA());
        stageRankA.setScore(stageRankA.getScore()+aScore);
        TournamentTeam tournamentTeamA = tournamentTeamMapper.selectByPrimaryKey(roundLog.getTournamentUserIdA());
        //如果是修改把上一次的成绩取消
        if(oldRoundLog.getRoundId()!=null){
            stageRankA.setScore(stageRankA.getScore() - oldRoundLog.getaScore());
            stageRankA.setImages("");
            //取消上次的成绩
            cancelGrade(oldRoundLog, stageRankA, tournamentTeamA,stage);

        }
        if(win==0){
            stageRankA.setDraw(stageRankA.getDraw()+1);
            setHistory(stageRankA,"D");
            tournamentTeamA.setDraw(tournamentTeamA.getDraw()+1);

            stageRankMapper.updateByPrimaryKeySelective(stageRankA);
        }else
        if(win.equals(tournamentTeamA.getTournamentUserId())){
            tournamentTeamA.setWin(tournamentTeamA.getWin()+1);
            stageRankA.setWin(stageRankA.getWin() + 1);
            setHistory(stageRankA,"W");
            stageRankMapper.updateByPrimaryKeySelective(stageRankA);
        }else {
            tournamentTeamA.setLose(tournamentTeamA.getLose()+1);
            stageRankA.setLose(stageRankA.getLose() + 1);
            setHistory(stageRankA,"L");
//            loseRank(stageRankA, stage,roundLog,false,tournamentTeamA);
        }

        StageRank stageRankB = stageRankMapper.findByStageIdAndUserId(roundLog.getStageId(),roundLog.getTournamentUserIdB());
        if(stageRankB!=null){
            stageRankB.setScore(stageRankB.getScore()+bScore);
        }
        TournamentTeam tournamentTeamB = tournamentTeamMapper.selectByPrimaryKey(roundLog.getTournamentUserIdB());
        if(tournamentTeamB!=null&&stageRankB != null){
            if(oldRoundLog.getRoundId()!=null){
                //取消上次的成绩
                stageRankB.setScore(stageRankB.getScore() - oldRoundLog.getbScore());
                stageRankB.setImages("");
                cancelGrade(oldRoundLog, stageRankB, tournamentTeamB,stage);

            }
            if(win==0){
                stageRankB.setDraw(stageRankB.getDraw()+1);
                setHistory(stageRankB,"D");
                tournamentTeamB.setDraw(tournamentTeamB.getDraw()+1);
                stageRankMapper.updateByPrimaryKeySelective(stageRankB);
            }else if(win.equals(tournamentTeamB.getTournamentUserId())){
                stageRankB.setWin(stageRankB.getWin()+1);
                setHistory(stageRankB,"W");
                tournamentTeamB.setWin(tournamentTeamB.getWin()+1);
                stageRankMapper.updateByPrimaryKeySelective(stageRankB);
            }else {
                stageRankB.setLose(stageRankB.getLose()+1);
                setHistory(stageRankB,"L");
                tournamentTeamB.setLose(tournamentTeamB.getLose()+1);
//                loseRank(stageRankB, stage, roundLog,false, tournamentTeamB);
            }
            tournamentTeamMapper.updateByPrimaryKey(tournamentTeamB);
        }


        if(loserId.equals(stageRankA.getTournamentUserId())){
            loseRank(stageRankA, stage, roundLog,false, tournamentTeamA);
        }else {
            loseRank(stageRankB, stage, roundLog,false, tournamentTeamB);
        }


        tournamentTeamMapper.updateByPrimaryKey(tournamentTeamA);


        List<Round> rounds = roundMapper.selectByStageId(stage.getId());

        //晋级到下一轮
        if(stage.getFormat().equals(Const.GAME_FORMAT_DOUBLE) || stage.getFormat().equals(Const.GAME_FORMAT_SINGLE)){

            for (int i = 0; i < rounds.size(); i++) {
                //如果不是最后一轮 晋级到下一轮
                if(rounds.get(i).getRoundId().equals(roundLog.getRoundId())&&i<rounds.size()-1){
                    List<RoundLog> roundLogs = roundLogMapper.selectByRound(rounds.get(i+1).getRoundId(),1);
                    //胜者组
                    if(roundLog.getType() == 1){
                        for (RoundLog value : roundLogs) {
                            if (value.getTournamentUserIdA() == null) {
                                value.setTournamentUserIdA(win);
                                roundLogMapper.updateByPrimaryKeySelective(value);
                                break;
                            }else
                            if (value.getTournamentUserIdB() == null) {
                                value.setTournamentUserIdB(win);
                                roundLogMapper.updateByPrimaryKeySelective(value);
                                break;
                            }
                        }
                        //双败制 胜者组进入败者组
                        if(stage.getFormat().equals(Const.GAME_FORMAT_DOUBLE)){
                            List<RoundLog> loser = roundLogMapper.selectByStage(rounds.get(i).getStageId(),2);
                            for (RoundLog log : loser) {
                                if (log.getTournamentUserIdA() == null) {
                                    log.setTournamentUserIdA(loserId);
                                    roundLogMapper.updateByPrimaryKeySelective(log);
                                    break;
                                }else
                                if (log.getTournamentUserIdB() == null) {
                                    log.setTournamentUserIdB(loserId);
                                    roundLogMapper.updateByPrimaryKeySelective(log);
                                    break;
                                }
                            }
                        }
                    }
                    //双败制 败者组败者淘汰胜者进入败者组下一轮
                    if(stage.getFormat().equals(Const.GAME_FORMAT_DOUBLE) && roundLog.getType() == 2){
                        List<RoundLog> loser = roundLogMapper.selectByRound(rounds.get(i+1).getRoundId(),2);
                        for (RoundLog log : loser) {
                            if (log.getTournamentUserIdA() == null) {
                                log.setTournamentUserIdA(win);
                                roundLogMapper.updateByPrimaryKeySelective(log);
                                break;
                            }else
                            if (log.getTournamentUserIdB() == null) {
                                log.setTournamentUserIdB(win);
                                roundLogMapper.updateByPrimaryKeySelective(log);
                                break;
                            }
                        }
                        //败者组的最后一个剩出者进入决赛
                        if(loser.size() == 0 && i==rounds.size()-2){
                            List<RoundLog> finalRound = roundLogMapper.selectByRound(rounds.get(i+1).getRoundId(),1);
                            for (RoundLog log : finalRound) {
                                if (log.getTournamentUserIdA() == null) {
                                    log.setTournamentUserIdA(win);
                                    roundLogMapper.updateByPrimaryKeySelective(log);
                                    break;
                                }else
                                if (log.getTournamentUserIdB() == null) {
                                    log.setTournamentUserIdB(win);
                                    roundLogMapper.updateByPrimaryKeySelective(log);
                                    break;
                                }
                            }
                        }
                    }

                }
            }


            //最后一轮
            if(roundLog.getRoundId().equals(rounds.get(rounds.size()-1).getRoundId()) ){
                //胜者组确定第二名和第一名
                if(roundLog.getType() == 1){
                    //确定第二名和第一名
                    if (stageRankA.getTournamentUserId().equals(loserId)){
                        //双败制需要确定第二名
                        if(stage.getFormat().equals(Const.GAME_FORMAT_DOUBLE)){
                            loseRank(stageRankA,stage,roundLog,true, tournamentTeamA);
                            stageRankMapper.updateByPrimaryKeySelective(stageRankA);
                        }
                        //单败制只确定第一名
                        loseRank(stageRankB,stage,roundLog,true, tournamentTeamB);
                        stageRankMapper.updateByPrimaryKeySelective(stageRankB);
                    }else {
                        if(stage.getFormat().equals(Const.GAME_FORMAT_DOUBLE)){
                            loseRank(stageRankB,stage,roundLog,true, tournamentTeamB);
                            stageRankMapper.updateByPrimaryKeySelective(stageRankB);
                        }
                        loseRank(stageRankA,stage,roundLog,true, tournamentTeamA);
                        stageRankMapper.updateByPrimaryKeySelective(stageRankA);

                    }
                }else {
                    List<RoundLog> roundLogs = roundLogMapper.selectByStage(stage.getId(),1);
                    for (RoundLog value : roundLogs) {
                        if (value.getTournamentUserIdA() == null) {
                            value.setTournamentUserIdA(win);
                            roundLogMapper.updateByPrimaryKeySelective(value);
                            break;
                        }else
                        if (value.getTournamentUserIdB() == null) {
                            value.setTournamentUserIdB(win);
                            roundLogMapper.updateByPrimaryKeySelective(value);
                            break;
                        }
                    }
                }

            }
        }



        return ResultGenerator.genSuccessResult();
    }

    /**
     * 修改时取消上次的成绩
     * @param oldRoundLog
     * @param stageRankA
     * @param tournamentTeamA
     */
    private void cancelGrade(RoundLog oldRoundLog, StageRank stageRankA, TournamentTeam tournamentTeamA,Stage stage) {
        if(oldRoundLog.getResult().equals(tournamentTeamA.getTournamentUserId())){
            tournamentTeamA.setWin(tournamentTeamA.getWin()-1);
            tournamentTeamA.setRank(null);
            stageRankA.setWin(stageRankA.getWin()-1);
            stageRankA.setRank(null);
        } else
        if (oldRoundLog.getResult().equals(0L)){
            tournamentTeamA.setDraw(tournamentTeamA.getDraw()-1);
            tournamentTeamA.setRank(null);
            stageRankA.setDraw(stageRankA.getDraw()-1);
            stageRankA.setRank(null);
        }
        else {
            tournamentTeamA.setLose(tournamentTeamA.getLose()-1);
            tournamentTeamA.setRank(null);
            stageRankA.setLose(stageRankA.getLose()-1);
            stageRankA.setRank(null);
        }
        stageRankA.setHistory(stageRankA.getHistory().substring(0,stageRankA.getHistory().length()-1));
        tournamentTeamMapper.updateByPrimaryKey(tournamentTeamA);
        stageRankMapper.updateByPrimaryKey(stageRankA);



        List<Round> rounds = roundMapper.selectByStageId(stage.getId());

        //晋级信息取消
        if(stage.getFormat().equals(Const.GAME_FORMAT_DOUBLE) || stage.getFormat().equals(Const.GAME_FORMAT_SINGLE)){

            for (int i = 0; i < rounds.size(); i++) {
                if(rounds.get(i).getRoundId().equals(oldRoundLog.getRoundId())&&i<rounds.size()-1){
                    List<RoundLog> roundLogs = roundLogMapper.selectByRound(rounds.get(i+1).getRoundId(),1);
                    //胜者组
                    if(oldRoundLog.getType() == 1){
                        for (RoundLog value : roundLogs) {
                            if (value.getTournamentUserIdA()!=null && value.getTournamentUserIdA().equals(tournamentTeamA.getTournamentUserId())) {
                                value.setTournamentUserIdA(null);
                                roundLogMapper.updateByPrimaryKey(value);
                            }
                            if (value.getTournamentUserIdB()!=null && value.getTournamentUserIdB().equals(tournamentTeamA.getTournamentUserId())) {
                                value.setTournamentUserIdB(null);
                                roundLogMapper.updateByPrimaryKey(value);
                            }
                        }
                        //双败制 胜者组进入败者组
                        if(stage.getFormat().equals(Const.GAME_FORMAT_DOUBLE)){
                            List<RoundLog> loser = roundLogMapper.selectByRound(rounds.get(i).getRoundId(),2);
                            for (RoundLog log : loser) {
                                if (log.getTournamentUserIdB()!=null &&log.getTournamentUserIdB().equals(tournamentTeamA.getTournamentUserId())) {
                                    log.setTournamentUserIdB(null);
                                    roundLogMapper.updateByPrimaryKey(log);
                                }
                                if (log.getTournamentUserIdA()!=null && log.getTournamentUserIdA().equals(tournamentTeamA.getTournamentUserId())) {
                                    log.setTournamentUserIdA(null);
                                    roundLogMapper.updateByPrimaryKey(log);
                                }
                            }
                        }
                    }
                    //双败制 败者组败者淘汰胜者进入败者组下一轮
                    if(stage.getFormat().equals(Const.GAME_FORMAT_DOUBLE) && oldRoundLog.getType() == 2){
                        List<RoundLog> loser = roundLogMapper.selectByRound(rounds.get(i+1).getRoundId(),2);
                        for (RoundLog log : loser) {
                            if (log.getTournamentUserIdA()!=null && log.getTournamentUserIdA().equals(oldRoundLog.getTournamentUserIdA())) {
                                log.setTournamentUserIdA(null);
                                roundLogMapper.updateByPrimaryKey(log);
                            }
                            if (log.getTournamentUserIdB() !=null && log.getTournamentUserIdB().equals(oldRoundLog.getTournamentUserIdB())) {
                                log.setTournamentUserIdB(null);
                                roundLogMapper.updateByPrimaryKey(log);
                            }
                        }
                        //败者组的最后一个剩出者进入决赛
                        if(loser.size() == 0 && i==rounds.size()-2){
                            List<RoundLog> finalRound = roundLogMapper.selectByRound(rounds.get(i+1).getRoundId(),1);
                            for (RoundLog log : finalRound) {
                                if (log.getTournamentUserIdA()!=null && log.getTournamentUserIdA().equals(oldRoundLog.getTournamentUserIdA())) {
                                    log.setTournamentUserIdA(null);
                                    roundLogMapper.updateByPrimaryKey(log);
                                }
                                if (log.getTournamentUserIdB()!=null && log.getTournamentUserIdB().equals(oldRoundLog.getTournamentUserIdB())) {
                                    log.setTournamentUserIdB(null);
                                    roundLogMapper.updateByPrimaryKey(log);
                                }
                            }
                        }
                    }

                }
            }
        }
    }

    /**
     *
     * 输的人确定排名
     */
    private void loseRank(StageRank stageRankB, Stage stage, RoundLog roundLog, boolean isFinal, TournamentTeam tournamentTeamA) {
        if(stage.getFormat().equals(Const.GAME_FORMAT_DOUBLE) && !isFinal){
            //双败制败败者组才被淘汰
            if(roundLog.getType() == 2){
                //本阶段排名
                Integer last = stageRankMapper.lastLose(stage.getId(),stageRankB.getTournamentUserId());
                if(last == null){
                    //最后一名
                    Integer max = stageRankMapper.maxLose(stage.getId(),stageRankB.getTournamentUserId());
                    stageRankB.setRank(max);
                }else {
                    stageRankB.setRank(last-1);
                }
                //整体排名
                Integer lastTeam = tournamentTeamMapper.lastLose(stage.getTournamentId());
                if(lastTeam == null){
                    Integer maxTeam = tournamentTeamMapper.maxTeam(stage.getTournamentId());
                    tournamentTeamA.setRank(maxTeam);
                }else {
                    tournamentTeamA.setRank(lastTeam-1);
                }
                stageRankMapper.updateByPrimaryKey(stageRankB);
                tournamentTeamMapper.updateByPrimaryKey(tournamentTeamA);
            }
        } else
        if (stage.getFormat().equals(Const.GAME_FORMAT_ROUND)){
            stageRankMapper.updateByPrimaryKey(stageRankB);
            //未完成的对战
            List<RoundLog> roundLogs = roundLogMapper.selectByGroupNoResult(roundLog.getGroupName(),stage.getId(),false);
            //全部结束 确定排名
            if(roundLogs==null || roundLogs.size() <1){
                List<StageRank> all = stageRankMapper.selectByGroupOrderWin(roundLog.getGroupName(),stage.getId());
                for (int i = 0; i < all.size(); i++) {
                    all.get(i).setRank(i+1);
                    stageRankMapper.updateByPrimaryKeySelective(all.get(i));
                }
            }
        }
        else {
           //本阶段排名
           Integer last = stageRankMapper.lastLose(stage.getId(),stageRankB.getTournamentUserId());
           if(last == null){
               //最后一名
               Integer max = stageRankMapper.maxLose(stage.getId(),stageRankB.getTournamentUserId());
               stageRankB.setRank(max);
           }else {
               stageRankB.setRank(last-1);
           }
            stageRankMapper.updateByPrimaryKey(stageRankB);
            //整体排名
            Integer lastTeam = tournamentTeamMapper.lastLose(stage.getTournamentId());
            if(lastTeam == null){
                Integer maxTeam = tournamentTeamMapper.maxTeam(stage.getTournamentId());
                tournamentTeamA.setRank(maxTeam);
            }else {
                tournamentTeamA.setRank(lastTeam-1);
            }
            tournamentTeamMapper.updateByPrimaryKey(tournamentTeamA);
        }
    }

    private void setHistory(StageRank stageRankA,String w) {
        if(stageRankA.getHistory() == null){
            stageRankA.setHistory(w);
        }else {
            stageRankA.setHistory(stageRankA.getHistory()+w);
        }
    }

    @Override
    public Result swap(SwapRoundVo swapRoundVo) {
         Stage stage = stageMapper.selectByPrimaryKey(swapRoundVo.getRoundLogA().getStageId());
         if(!stage.getFormat().equals(Const.GAME_FORMAT_DOUBLE)&&!stage.getFormat().equals(Const.GAME_FORMAT_SINGLE)){
             return  ResultGenerator.genFailResult(400,"This format does not support exchange of team member");
         }

         update(swapRoundVo.getRoundLogA());
         update(swapRoundVo.getRoundLogB());
        return ResultGenerator.genSuccessResult();
    }
}
